package com.ithui.tidal.user.service.impl;

import cn.hutool.core.util.StrUtil;
import com.ithui.tidal.user.service.UserService;
import com.ithui.tidal.user.service.adapter.TextBuilder;
import com.ithui.tidal.user.service.adapter.UserAdapter;
import com.ithui.tidal.user.dao.UserDao;
import com.ithui.tidal.user.domain.entity.User;
import com.ithui.tidal.user.service.WXMsgService;
import com.ithui.tidal.websocket.domain.service.WebSocketService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

import java.net.URLEncoder;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 *@Author: ithui
 *@CreateTime: 2025-07-31
 */
@Service
@Slf4j
public class WXMsgServiceImpl implements WXMsgService {

    @Autowired
    private WebSocketService webSocketService;

    /**
     * openid和登录code的关系map
     */
    private static final ConcurrentHashMap<String,Integer> WAIT_AUTHORIZE_MAP = new ConcurrentHashMap<>();

    @Value("${tidal.wx.callback}")
    private String callback;

    // 微信授权链接
    public static final String URL = "https://open.weixin.qq.com/connect/oauth2/authorize?" +
            "appid=%s&redirect_uri=%s" + // 这里需要替换掉两个值
            "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";


    @Autowired
    private UserDao userDao;
    @Autowired
    private UserService userService;
    @Autowired
    @Lazy
    private WxMpService wxMpService;

    @Override
    public WxMpXmlOutMessage scan(WxMpXmlMessage wxMpXmlMessage) {
        String openId = wxMpXmlMessage.getFromUser();
        Integer code = getEventKey(wxMpXmlMessage);
        if(Objects.isNull(code)){
            return null;
        }
        User user = userDao.getByOpenId(openId);

        // 用户是否注册
        boolean registered = Objects.nonNull(user);
        // 用户是否授权
        boolean authorized = registered && StrUtil.isNotBlank(user.getAvatar());
        // 用户已经注册，校验头像是为了保证用户已经授权
        if(registered && authorized){
            //登录逻辑，通过code给Channel推送消息
            webSocketService.scanLoginSuccess(code,user.getId());
        }
        // 用户未注册
        if(!registered){
            User insert = UserAdapter.buildUserSave(openId);
            userService.register(insert);
        }
        // 推送链接让用户授权
        WAIT_AUTHORIZE_MAP.put(openId, code);
        webSocketService.waitAuthorize(code);
        String authorizeUrl = String.format(URL, wxMpService.getWxMpConfigStorage().getAppId(), URLEncoder.encode(callback + "/wx/portal/public/callBack"));
        System.out.println("authorizeUrl:" + authorizeUrl);
        return TextBuilder.build("请点击登录: <a href=\"" + authorizeUrl + "\">登录</a>", wxMpXmlMessage);

    }

    /**
     * 用户授权
     */
    @Override
    public void authorize(WxOAuth2UserInfo userInfo) {
        String openid = userInfo.getOpenid();
        User user = userDao.getByOpenId(openid);
        // 更新用户信息
        if(StrUtil.isBlank(user.getAvatar())){
            fillUserInfo(user.getId(), userInfo);
        }
        // 通过code找到用户channel进行登录
        Integer code = WAIT_AUTHORIZE_MAP.remove(openid);
        webSocketService.scanLoginSuccess(code,user.getId());
    }

    private void fillUserInfo(Long uid, WxOAuth2UserInfo userInfo) {
        // 更新用户信息
        User user = UserAdapter.buildAuthorizeUser(uid, userInfo);
        /*try{

        }catch (DuplicateKeyException e){
            // 唯一键冲突
        }*/
        userDao.updateById(user);

    }

    private Integer getEventKey(WxMpXmlMessage wxMpXmlMessage) {
        try{
            String eventKey = wxMpXmlMessage.getEventKey();
            // 事件码 qrscene_2
            String code = eventKey.replace("qrscene_", "");
            return Integer.parseInt(code);
        }catch (Exception e){
            log.error("getEventKey error eventKey:{}",wxMpXmlMessage.getEventKey(), e);
            return null;
        }
    }
}
